From ddd76b10af0a21e5c0d08d3101538adcb418551c Mon Sep 17 00:00:00 2001 From: Mke Brady Date: Wed, 7 Oct 2015 08:40:10 +0100 Subject: [PATCH 1/6] Add, untested, stuff to capture and remember a volume_range_db setting. --- common.h | 1 + configure.ac | 2 +- scripts/shairport-sync.conf | 1 + scripts/shairport-sync.conf~ | 81 ++++++++++++++++++++++++++++++++++++ shairport.c | 13 +++++- 5 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 scripts/shairport-sync.conf~ 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/scripts/shairport-sync.conf b/scripts/shairport-sync.conf index 8a4dbf72..0a9be12a 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 = 0; // set this to the range, in dB, you want between the maximum volume and the minimum volume. Zero means use the mixer's native range. Default is 0. }; // How to deal with metadata, including artwork diff --git a/scripts/shairport-sync.conf~ b/scripts/shairport-sync.conf~ new file mode 100644 index 00000000..8a4dbf72 --- /dev/null +++ b/scripts/shairport-sync.conf~ @@ -0,0 +1,81 @@ +// Sample Configuration File for Shairport Sync +// Commented out settings are generally the defaults, except where noted. + +// General Settings +general = +{ +// name = "Shairport Sync Player"; // This is the name the service will advertise to iTunes. The default is "Shairport Sync on " +// password = "secret"; // comment out this line if you want to have no password +// interpolation = "basic"; // aka "stuffing". Default is "basic", alternative is "soxr". Use "soxr" only if you have a reasonably fast processor. +// output_backend = "alsa"; // Run "shairport-sync -h" to get a list of all output_backends, e.g. "alsa", "pipe", "stdout". The default is the first one. +// mdns_backend = "avahi"; // Run "shairport-sync -h" to get a list of all mdns_backends. The default is the first one. +// port = 5000; // Listen for service requests on this port +// udp_port_base = 6001; // start allocating UDP ports from this port number when needed +// udp_port_range = 100; // look for free ports in this number of places, starting at the UDP port base (only three are needed). +// statistics = "no"; // set to "yes" to print statistics in the log +// drift = 88; // allow this number of frames of drift away from exact synchronisation before attempting to correct it +// 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. +}; + +// How to deal with metadata, including artwork +metadata = +{ +// enabled = "no"; // et to yes to get Shairport Sync to solicit metadata from the source and to pass it on via a pipe +// include_cover_art = "no"; // set to "yes" to get Shairport Sync to solicit cover art from the source and pass it via the pipe. You must also set "enabled" to "yes". +// pipe_name = "/tmp/shairport-sync-metadata"; +}; + +// Advanced parameters for controlling how a Shairport Sync runs +sessioncontrol = +{ +// run_this_before_play_begins = "/full/path/to/application and args"; // make sure the application has executable permission. It it's a script, include the #!... stuff on the first line +// run_this_after_play_ends = "/full/path/to/application and args"; // make sure the application has executable permission. It it's a script, include the #!... stuff on the first line +// wait_for_completion = "no"; // set to "yes" to get Shairport Sync to wait until the "run_this..." applications have terminated before continuing +// allow_session_interruption = "no"; // set to "yes" to allow another device to interrupt Shairport Sync while it's playing from an existing audio source +// session_timeout = 120; // wait for this number of seconds after a source disappears before terminating the session and becoming available again. +}; + +// +// Back End Settings +// + +// These are parameters for the "alsa" audio back end, the only back end that supports synchronised audio. +alsa = +{ +// output_device = "default"; // the name of the alsa output device. Use "alsamixer" or "aplay" to find out the names of devices, mixers, etc. +// mixer_control_name = "PCM"; // the name of the mixer to use to adjust output volume. If not specified, volume in adjusted in software. +// mixer_device = "default"; // the mixer_device default is whatever the output_device is. Normally you wouldn't have to use this. +// audio_backend_latency_offset = 0; // Set this offset to compensate for a fixed delay in the audio back end. E.g. if the output device delays by 100 ms, set this to -4410. +// audio_backend_buffer_desired_length = 6615; // If set too small, buffer underflow occurs on low-powered machines. Too long and the response times with software mixer become annoying. +}; + +// These are parameters for the "pipe" audio back end, a back end that directs raw CD-style audio output to a pipe. No interpolation is done. +pipe = +{ +// name = "/path/to/pipe"; // there is no default pipe name for the output +// audio_backend_latency_offset = 0; // Set this offset to compensate for a fixed delay in the audio back end. E.g. if the output device delays by 100 ms, set this to -4410. +// audio_backend_buffer_desired_length = 44100; // Having started to send audio at the right time, send all subsequent audio this many frames ahead of time, creating a buffer this size. +}; + +// These are parameters for the "stdout" audio back end, a back end that directs raw CD-style audio output to stdout. No interpolation is done. +stdout = +{ +// audio_backend_latency_offset = 0; // Set this offset to compensate for a fixed delay in the audio back end. E.g. if the output device delays by 100 ms, set this to -4410. +// audio_backend_buffer_desired_length = 44100; // Having started to send audio at the right time, send all subsequent audio this many frames ahead of time, creating a buffer this size. +}; + +// The following static latency settings are deprecated -- do not use them for new installations. Shairport Sync now sets latencies automatically. +// To compensate for a delay in the output device using the alsa/stdio/pipe "audio_backend_latency_offset" setting. + +// Static latencies for different sources. These have been estimated from listening tests. +latencies = +{ +// default = 88200; // used for unrecognised sources and for iTunes up to and including iTunes 9.X. +// itunes = 99400; // used for iTunes 10 or later +// airplay = 88200; +// forkedDaapd = 99400; +}; + + diff --git a/shairport.c b/shairport.c index beb8d21b..a17fa86b 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", &value)) { + if ((value < 0) || (value > 200)) + die("Invalid volume range \"%sd\". It should be between 0 and 200. 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) { From 97a83c810a0b09f94272b9c1bee8bf904138a2f9 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Wed, 7 Oct 2015 14:31:20 +0100 Subject: [PATCH 2/6] Delete shairport-sync.conf~ Included by mhistake! --- scripts/shairport-sync.conf~ | 81 ------------------------------------ 1 file changed, 81 deletions(-) delete mode 100644 scripts/shairport-sync.conf~ diff --git a/scripts/shairport-sync.conf~ b/scripts/shairport-sync.conf~ deleted file mode 100644 index 8a4dbf72..00000000 --- a/scripts/shairport-sync.conf~ +++ /dev/null @@ -1,81 +0,0 @@ -// Sample Configuration File for Shairport Sync -// Commented out settings are generally the defaults, except where noted. - -// General Settings -general = -{ -// name = "Shairport Sync Player"; // This is the name the service will advertise to iTunes. The default is "Shairport Sync on " -// password = "secret"; // comment out this line if you want to have no password -// interpolation = "basic"; // aka "stuffing". Default is "basic", alternative is "soxr". Use "soxr" only if you have a reasonably fast processor. -// output_backend = "alsa"; // Run "shairport-sync -h" to get a list of all output_backends, e.g. "alsa", "pipe", "stdout". The default is the first one. -// mdns_backend = "avahi"; // Run "shairport-sync -h" to get a list of all mdns_backends. The default is the first one. -// port = 5000; // Listen for service requests on this port -// udp_port_base = 6001; // start allocating UDP ports from this port number when needed -// udp_port_range = 100; // look for free ports in this number of places, starting at the UDP port base (only three are needed). -// statistics = "no"; // set to "yes" to print statistics in the log -// drift = 88; // allow this number of frames of drift away from exact synchronisation before attempting to correct it -// 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. -}; - -// How to deal with metadata, including artwork -metadata = -{ -// enabled = "no"; // et to yes to get Shairport Sync to solicit metadata from the source and to pass it on via a pipe -// include_cover_art = "no"; // set to "yes" to get Shairport Sync to solicit cover art from the source and pass it via the pipe. You must also set "enabled" to "yes". -// pipe_name = "/tmp/shairport-sync-metadata"; -}; - -// Advanced parameters for controlling how a Shairport Sync runs -sessioncontrol = -{ -// run_this_before_play_begins = "/full/path/to/application and args"; // make sure the application has executable permission. It it's a script, include the #!... stuff on the first line -// run_this_after_play_ends = "/full/path/to/application and args"; // make sure the application has executable permission. It it's a script, include the #!... stuff on the first line -// wait_for_completion = "no"; // set to "yes" to get Shairport Sync to wait until the "run_this..." applications have terminated before continuing -// allow_session_interruption = "no"; // set to "yes" to allow another device to interrupt Shairport Sync while it's playing from an existing audio source -// session_timeout = 120; // wait for this number of seconds after a source disappears before terminating the session and becoming available again. -}; - -// -// Back End Settings -// - -// These are parameters for the "alsa" audio back end, the only back end that supports synchronised audio. -alsa = -{ -// output_device = "default"; // the name of the alsa output device. Use "alsamixer" or "aplay" to find out the names of devices, mixers, etc. -// mixer_control_name = "PCM"; // the name of the mixer to use to adjust output volume. If not specified, volume in adjusted in software. -// mixer_device = "default"; // the mixer_device default is whatever the output_device is. Normally you wouldn't have to use this. -// audio_backend_latency_offset = 0; // Set this offset to compensate for a fixed delay in the audio back end. E.g. if the output device delays by 100 ms, set this to -4410. -// audio_backend_buffer_desired_length = 6615; // If set too small, buffer underflow occurs on low-powered machines. Too long and the response times with software mixer become annoying. -}; - -// These are parameters for the "pipe" audio back end, a back end that directs raw CD-style audio output to a pipe. No interpolation is done. -pipe = -{ -// name = "/path/to/pipe"; // there is no default pipe name for the output -// audio_backend_latency_offset = 0; // Set this offset to compensate for a fixed delay in the audio back end. E.g. if the output device delays by 100 ms, set this to -4410. -// audio_backend_buffer_desired_length = 44100; // Having started to send audio at the right time, send all subsequent audio this many frames ahead of time, creating a buffer this size. -}; - -// These are parameters for the "stdout" audio back end, a back end that directs raw CD-style audio output to stdout. No interpolation is done. -stdout = -{ -// audio_backend_latency_offset = 0; // Set this offset to compensate for a fixed delay in the audio back end. E.g. if the output device delays by 100 ms, set this to -4410. -// audio_backend_buffer_desired_length = 44100; // Having started to send audio at the right time, send all subsequent audio this many frames ahead of time, creating a buffer this size. -}; - -// The following static latency settings are deprecated -- do not use them for new installations. Shairport Sync now sets latencies automatically. -// To compensate for a delay in the output device using the alsa/stdio/pipe "audio_backend_latency_offset" setting. - -// Static latencies for different sources. These have been estimated from listening tests. -latencies = -{ -// default = 88200; // used for unrecognised sources and for iTunes up to and including iTunes 9.X. -// itunes = 99400; // used for iTunes 10 or later -// airplay = 88200; -// forkedDaapd = 99400; -}; - - From ea250113941d4ea80bd2e93e95feb68b03e5717a Mon Sep 17 00:00:00 2001 From: Mke Brady Date: Wed, 7 Oct 2015 22:33:20 +0100 Subject: [PATCH 3/6] Functional volume_range_db setting in the general stanza --- audio_alsa.c | 7 +++++++ player.c | 19 +++++++++++++------ scripts/shairport-sync.conf | 2 +- shairport.c | 6 +++--- 4 files changed, 24 insertions(+), 10 deletions(-) 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/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 0a9be12a..28eca89e 100644 --- a/scripts/shairport-sync.conf +++ b/scripts/shairport-sync.conf @@ -17,7 +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 = 0; // set this to the range, in dB, you want between the maximum volume and the minimum volume. Zero means use the mixer's native range. Default is 0. +// 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 a17fa86b..91f2fb85 100644 --- a/shairport.c +++ b/shairport.c @@ -400,9 +400,9 @@ int parse_options(int argc, char **argv) { } /* 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", &value)) { - if ((value < 0) || (value > 200)) - die("Invalid volume range \"%sd\". It should be between 0 and 200. Zero means use the mixer's native range", + 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; From b3c2d97be75e7603caec4eb71214f0c464ba7865 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 9 Oct 2015 13:39:11 +0100 Subject: [PATCH 4/6] Update RELEASENOTES.md --- RELEASENOTES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a0dc9ae8..9ae73eb4 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 `general` setting `volume_range_db` 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, whcih 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** From df99489b185ee406da83a093d7d9b606aba77750 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 9 Oct 2015 13:40:13 +0100 Subject: [PATCH 5/6] Update RELEASENOTES.md --- RELEASENOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 9ae73eb4..4f9336b3 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,7 +1,7 @@ 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 `general` setting `volume_range_db` 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, whcih feeds the headphone jack, is 35. Using it in this case gives the volume control a much more useful range of volumes. +* 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 `general` setting `volume_range_db` 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 ---- From 71ccee32fd5fb81214d705a9f31f77ba6f620d57 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 9 Oct 2015 13:59:35 +0100 Subject: [PATCH 6/6] Update RELEASENOTES.md --- RELEASENOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 4f9336b3..7ad0bfe2 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,7 +1,7 @@ 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 `general` setting `volume_range_db` 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. +* 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 ----