amixer volume control

Status
This old topic is closed. If you want to reopen this topic, contact a moderator using the "Report Post" button.
I'm going to rewrite volume control in Peppy player and use 'amixer' instead of volume control functionality of each player (mpd, mplayer or vlc).

Right now the player has linear scale 0-100. It looks like 'amixer' has a logarithmic scale even when you change volume from 0% to 100%. It's almost not audible after 35%:

amixer set PCM 35%
Simple mixer control 'PCM',0
Capabilities: pvolume pswitch pswitch-joined
Playback channels: Front Left - Front Right
Limits: Playback -10239 - 400
Mono:
Front Left: Playback -6515 [35%] [-65.15dB] [on]
Front Right: Playback -6515 [35%] [-65.15dB] [on]

Should I use some logarithmic calculation to convert amixer's 0-100% range to the linear scale? Otherwise almost 1/3 of the software UI volume control or hardware rotary encoder will be unusable.
Thanks!
 
Very few soundcards implement volume control in analog domain, most soundcards use digital volume control, if they offer a volume control feature. For them it does not make any difference whether the sample division by a fixed number is performed by the player, by alsa softvol plugin, or by a DSP hardware in the DAC chip.

Actually most of the analog-volume soundcards are on-board Intel-HDAs with HDA codecs.

In my embedded player with the onboard Intel-HDA (analog control) and MPV GitHub - pavhofman/plabs-player the first volume steps of the soundcard were too coarse, with sound at 0% still audible. I ended up using both alsa analog volume and MPV digital volume, where MPV reduced volume from 100% to 0% for the lowest 20% of the volume range:

100% required -> 100% alsa/100% MPV
50% required -> 50% alsa/100% MPV
20% required -> 20% alsa/100% MPV
19% required -> 19% alsa/95% MPV
10% required -> 10% alsa/50% MPV
1% required -> 1% alsa/5% MPV
0% required -> 0% alsa/0% MPV - silence

Combining both can produce any volume curve as required.

plabs-player/player.py at ff65b9f85fe32e2582f7fbea47d34b33a5e441c5 * pavhofman/plabs-player * GitHub


plabs-player/player.py at ff65b9f85fe32e2582f7fbea47d34b33a5e441c5 * pavhofman/plabs-player * GitHub

plabs-player/mixer.py at ff65b9f85fe32e2582f7fbea47d34b33a5e441c5 * pavhofman/plabs-player * GitHub
 
I saw similar approach (mopidy ?) where you can define the range of your volume in the config file. For example - minimum will be at 30% and maximum at 80% of the ALSA scale. That looks a bit complicated to me. '-M' option gives what I need. Though I'm not sure that you can specify this option if you use 'alsaaudio' Python bindings.
 
Actually I did not define a limited range of alsa values, but changed the shape of the alsa volume curve (not going to silence at 0, first steps too coarse) with internal player volume control.

But to your issue. If you look at amixer playback values - your available range of values is from -10239 to 400. All the -M parameter does in amixer is map this range to 0 - 100, e.g. alsa-utils/amixer.c at 805d30b260d0f7f7c4453ef09e11f2c3f1b548d5 * alsa-project/alsa-utils * GitHub

pyalsaaudio operates in 0-100 values too:

Getting volume - conversion from raw alsa value using min a max values to percentage value - linear mapping pyalsaaudio/alsaaudio.c at master * larsimmisch/pyalsaaudio * GitHub

Setting volume - conversion from percentage value to alsa raw value (physvolume in code) between min and max pyalsaaudio/alsaaudio.c at master * larsimmisch/pyalsaaudio * GitHub
 
The min/max values are reported by the alsa control element and stored in internal pyalsaaudio params pmin, pmax (cmin, cmax for capture) pyalsaaudio/alsaaudio.c at master * larsimmisch/pyalsaaudio * GitHub . Pyalsaaudio uses them for transposition between alsa control range and the percentage <0 , 100> range used by your python code.

Using amixer -M does the same thing.

The Intel HDA in my player offered only 64 steps. Pyalsaaudio (I use that library too) converted between 0 - 100 and 0 - 64 which unaviodably led to ugly coarse steps in low volumes. That is why I smoothed it with the player volume functionality (i.e. software volume).
 
Do you mean the mix of soundcard and player volume control? In my case I wanted to keep the analog volume control of the onboard soundcard to keep potential noise at minimum, hence the mixed solution. If a soundcard offers 100+ volume steps (i.e. digital volume control) and the min level produces no sound, there is no reason to complicate it with the player volume.
 
Finally I have a time to play with pyalsaaudio and it looks like it doesn't change volume in a linear scale. It has testing program mixertest.py:
pyalsaaudio/mixertest.py at master * larsimmisch/pyalsaaudio * GitHub

I tried to run it and compare the result with 'amixer' and -M option. Here is what I got:

Code:
pi@raspberrypi:~ $ python3 mixertest.py PCM 50
Available sound cards:
  0: bcm2835 ALSA (bcm2835 ALSA)

pi@raspberrypi:~ $ amixer sget PCM -M
Simple mixer control 'PCM',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback -10239 - 400
  Mono: Playback -4919 [13%] [-49.19dB] [on]

pi@raspberrypi:~ $ amixer sset PCM 50% -M
Simple mixer control 'PCM',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback -10239 - 400
  Mono: Playback -1406 [50%] [-14.06dB] [on]

pi@raspberrypi:~ $ amixer sget PCM -M
Simple mixer control 'PCM',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback -10239 - 400
  Mono: Playback -1406 [50%] [-14.06dB] [on]
The first command should set volume to 50% in linear scale but it set it to 13%. If I do that with 'amixer' and -M option it works fine.
 
IMO pyalsa does what its source code shows - sets the value at required percentage between min and max:


Code:
pi@raspberrypi:~ $ amixer sget PCM -M
Simple mixer control 'PCM',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback -10239 - 400
  Mono: Playback -4919 [13%] [-49.19dB] [on]

However, what if that scale is dB and you want linear ratio? amixer knows this and recalculates the value to fit linear scale:

Code:
pi@raspberrypi:~ $ amixer sset PCM 50% -M
Simple mixer control 'PCM',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback -10239 - 400
  Mono: Playback -1406 [50%] [-14.06dB] [on]

Notice that -1406 is not half way (50%) between -10239 and 400. But if those steps are logarithmic (each step 1/100 dB), it is half way in linear terms.

Values in the alsa control elements are accompanied by explanation of their meaning - TLVs. Amixer is parsing that too alsa-utils/amixer.c at master * alsa-project/alsa-utils * GitHub , unlike pyalsa which just reads the min, max values and calculates the required percentage pyalsaaudio/alsaaudio.c at master * larsimmisch/pyalsaaudio * GitHub
 
Last edited:
Yes, pyalsaaudio can change volume only using logarithmic scale where 50% of your volume slider position means 13% of volume output. I'm not sure if there is a way to make it working using a linear scale as well. This is strange as 'amixer' supports both.

I had an idea to let user select either linear or logarithmic scale. So in this case I should probably call 'amixer' directly from my code rather than using pyalsaaudio for volume control.
 
Well, pyalsaaudio is a small auxiliary project whereas amixer is key part of the alsa sound layer, used also for showing third-party devels how to do the stuff properly.

Either calling amixer directly, or adding the functionality to pyalsaaudio, or doing the calculation in your code (if min/max values are not required for the calculation which they probably are).
 
Converting from linear to logarithmic scale in the code is another option. Maximum ALSA volume level could be also changed in UI. Are there anything else which would make sense to let user to configure? Switching between hardware/software volume control?
 
In my all-in-one player the first steps of the soundcard volume were too coarse, I had to combine hw alsa volume with softvol by the player (mpv in my case) - the range 0 - 20% mapped to 0 - 100% of mpv softvol + 0 - 20% of alsa, for above 20% mpv was at 100%, volume by alsa only.
 
In my all-in-one player the first steps of the soundcard volume were too coarse, I had to combine hw alsa volume with softvol by the player (mpv in my case) - the range 0 - 20% mapped to 0 - 100% of mpv softvol + 0 - 20% of alsa, for above 20% mpv was at 100%, volume by alsa only.


Do you mean that mpv volume was set to 100% and you changed only ALSA level? Just wondering how that could be configured in UI?
 
Now I see what you mean. My setup is hardcoded, for the given hardware. Actually it involves just one number - the threshold (20%) where the software volume reaches 100%. But if your HW volume is OK, no reason to complicate it with this. My soundcard volume did not reach silence at 0 and at 10 it was already quite loud.

BTW what is the advantage of the linear scale? Log is much more natural volume control than linear. Or you can shape any curve you like :)
 
Status
This old topic is closed. If you want to reopen this topic, contact a moderator using the "Report Post" button.