We have talked about some of the volume APIs Windows exposes. We have also talked about what it means for a volume control to be linear in magnitude, linear in power, or linear in dB.
The attachment to this blog post contains:
- An app I wrote to exercise the IAudioStreamVolume, ISimpleAudioVolume, IChannelAudioVolume, and IAudioEndpointVolume APIs
- An Excel spreadsheet with the analysis of the output of the app
Let's start by looking at what the app does.
volume-linearity.exe --signal | --stream | --session | --channel |
--endpoint-db | --capture
--signal varies the amplitude of the generated signal from 0 to 1
--stream varies the IAudioStreamVolume from 0 to 1
--session varies the ISimpleAudioVolume from 0 to 1
--channel varies the IChannelAudioVolume from 0 to 1
--endpoint-db varies the IAudioEndpointVolume from X dB to Y dB
where X and Y are the min and max values supported
--capture varies session, channel, and endpoint-db volumes
on the default capture device
Let's look at --signal mode first. The app plays a square wave at amplitudes from 0 (silence) to 1 (full-scale), varying in a linearly in magnitude. It takes periodic readings using IAudioMeterInformation to see what the peak values on the other side of the audio engine are. The IAudioMeterInformation API returns readings that are also linear in magnitude, so the response graph looks nice and linear:
Well... wait a second. What happened at full scale? Let's get a closer look:
When we attempt to play a square wave of amplitude greater than about 0.985, the meter reveals that what we get out of the audio engine is not quite what we put in. The volume has been capped. What's going on?
If we look at the list of WASAPI Audio Processing objects, notice that one of them is called CAudioLimiter. The job of this APO is to take its input and produce output that is limited to the range (-1, 1). When it sees that signals are getting too close to the edge, it steps in and pulls the signal closer to the center.
For this reason, the other modes of volume-linearity.exe use a half-scale (-1/2, 1/2) square wave rather than a full-scale square wave.
UPDATE June 1 2011: added --capture mode
UPDATE September 28 2015: moved source to https://github.com/mvaneerde/blog/tree/master/volume-linearity