AirPlay, Shairport Sync, ALSA and Volume Control

This is a quick post about AirPlay, Shairport Sync, ALSA and volume control. I mainly play vinyl but when I stream Spotify I usually do it from my Mac to my DIY AirPlay receiver. It is built around a Raspberry Pi 2 Model B with a HiFiBerry DAC+ running Shairport Sync. I can not praise Mike Brady enough for the time and  effort he has put into this stellar piece of software.

The HiFiBerry DAC+ is capable of outputting some 2 Vrms but I wanted to explore the difference between the different options for volume control. Why? Because the Spotify application got a volume control. My Mac got a volume output setting (often controlled by the keys F12 (volume up) and F11 (volume down). My AirPlay receiver got volume control in ALSA and Shairport Sync. How does it all add up? This is what drove me to make some tests and I am documenting my results in case it might be of interest for somebody else.

I conducted these tests sending a test signal (1 kHz) from my Mac over AirPlay to my AirPlay receiver. I measured the output voltage from the HiFiBerry DAC+ with a true Vrms digital multi-meter. The test signal was measured for each step of the volume control on the Mac. From 0% (mute) up to 100%. I used the resolution of the F11 and F12 buttons. These are the steps on the Mac in percent:

100

94

88

81

75

69

63

56

50

44

38

31

25

19

13

6

0

 And this is how they plot in a chart:

It seems totally linear compared to the logarithmic volume control (stepped attenuator) on my preamp:

But the stepped attenuator is expressed in dB so how is the linear percentage on the Mac volume control mapped to output voltage on my AirPlay receiver? Shairport Sync is using software volume control by default. It also uses the mixer's native range and a standard profile (somewhat logarithmic) by default. This can all be configured to your liking. 

The easiest way to measure how the volume control in percentage on my Mac is translated to my AirPlay receiver is to reconfigure Shairport Sync to use hardware volume control and read the corresponding value in alsamixer. This is what I got with the mixer's native range, standard and flat profile:

AirPlay %

ALSA HW Standard %

ALSA HW Flat %

100

100

100

94

87

78

88

78

61

81

68

47

75

61

37

69

53

29

63

47

22

56

38

17

50

30

14

44

24

11

38

20

8

31

16

7

25

12

5

19

10

4

13

6

3

6

3

2

0

2

2

And this is what it looks like in a chart:

I find it a bit strange that the flat profile seems more logarithmic than the standard profile.

But this is all in percent what about dB and Vrms? And is there any differences between hardware and software volume control? These are the Vrms values measured for each step (the values for software volume control was taken with ALSA mixer @ 100%):

ALSA HW Standard Vrms

ALSA HW Flat Vrms

ALSA SW Standard Vrms

ALSA SW Flat Vrms

2,127

2,127

2,128

2,127

1,418

1,0051

1,5001

1,0621

1,0051

0,4766

1,0621

0,5322

0,6725

0,2258

0,7519

0,2665

0,4765

0,1069

0,5322

0,1334

0,3187

0,0505

0.3767

0,0667

0,2258

0,0238

0,2665

0,0332

0,1132

0,0111

0,1429

0,0164

0,06

0,0055

0,0766

0,0080

0,0299

0,0025

0,0409

0,0040

0,0157

0,0014

0,0218

0,0020

0,0078

0,001

0,0115

0,0013

0,0041

0,0008

0,0061

0,0010

0,002

0,0009

0,0031

0,0009

0,0014

0,0009

0,0012

0,0009

0,001

0,0009

0,0010

0,0009

0,0009

0,0009

0,0009

0,0009

And this is what it looks like in a chart:

My takeaway from this is that it is no major difference from a Vrms point of view between hardware and software volume control. But it might depend on your native range. My HiFiBerry DAC+ got a native range of 0..-103.5 dB, amixer reports:

numid=1,iface=MIXER,name='Digital Playback Volume'
  ; type=INTEGER,access=rw---R--,values=2,min=0,max=207,step=0
  : values=157,157
  | dBscale-min=-103.50dB,step=0.50dB,mute=1

To me this is far from optimal. My preamps stepped attenuator got a range of 0..-62 dB and I think that is pretty perfect. One way to correct this is to use the volume_range_db setting in Shairport Sync. This is the difference between the native mixer range (default) and volume_range_db = 60;

AirPlay %

ALSA HW Standard %

ALSA HW Standard Vrms

ALSA HW Standard 60dB %

ALSA HW Standard 60dB Vrms

100

100

2,127

100

2,128

94

87

1,418

93

1,6842

88

78

1,0051

86

1,3391

81

68

0,6725

79

1,0645

75

61

0,4765

75

0,8962

69

53

0,3187

69

0,7123

63

47

0,2258

64

0,5662

56

38

0,1132

56

0,3788

50

30

0,06

50

0,2683

44

24

0,0299

44

0,1794

38

20

0,0157

38

0,1200

31

16

0,0078

33

0,0802

25

12

0,0041

30

0,0567

19

10

0,002

26

0,0378

13

6

0,0014

19

0,0155

6

3

0,001

14

0,0055

0

2

0,0009

2

0,0014

And this is what it looks like in charts:

Is this useful? Lets say you feed your Airplay receiver to a preamp with an input sensitivity of 1.0 Vrms. You also want the AirPlay volume control to span 0..-60 dB. Using my Airplay receiver as an example the output of the Airplay Receiver can be as much as 2.128 Vrms. ALSA HW Standard 60 dB equals 1.0645 Vrms @ 79%. Set ALSA mixer to 79% (and save it with "sudo alsactl store") and use Shairport Sync software volume control with volume_range_db = 60; Max volume will now be 1.0645 Vrms and the range of the volume control will be 0..-60 dB.

With flexibility comes complexity but sometimes it is needed to get things totally right...