Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial support for ALSA mixer #45

Closed
sashahilton00 opened this issue Jan 29, 2018 · 11 comments
Closed

Add initial support for ALSA mixer #45

sashahilton00 opened this issue Jan 29, 2018 · 11 comments

Comments

@sashahilton00
Copy link
Member

Issue by joerg-krause
Thursday Mar 09, 2017 at 09:35 GMT
Originally opened as plietar/librespot#160


The ALSA mixer module implements a simple linear volume control. Note, that a linear volume control is not ideal for human audio experience as our ears respond to sound on an exponential curve.

The mixer also works fine with the ALSA softvol plugin which offers an logarithmic attenuation curve.

TODO: Use logarithmic curve for hardware mixers.


joerg-krause included the following code: https://github.com/plietar/librespot/pull/160/commits

@sashahilton00
Copy link
Member Author

Comment by jsopenrb
Wednesday Mar 15, 2017 at 19:24 GMT


Volume calculation fails for maximum volume values. If the range is 0..255 then at full volume the result will be 256 instead of 255. I suppose it should not use integer math because volume range can have very different values.

@sashahilton00
Copy link
Member Author

Comment by joerg-krause
Wednesday Mar 15, 2017 at 19:47 GMT


Not sure what do you mean. The mixer uses get_playback_volume_range() to get the actual range.

@sashahilton00
Copy link
Member Author

Comment by jsopenrb
Wednesday Mar 15, 2017 at 20:10 GMT


Yes, but then you add one to that range, so for 0..255 at max volume the
resulting volume is 256 instead of 255.

On Wednesday, March 15, 2017, Jörg Krause notifications@github.com wrote:

Not sure what do you mean. The mixer uses get_playback_volume_range() to
get the actual range.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.<
https://ci5.googleusercontent.com/proxy/iVB_IHPdVhUghRc1w6iFL7sz5ZWPm2tTGJe3eGNbAdIXtfxoXO_m9LY1LBXbk8LjAZLtoB6Qm0lwbQj5Nvd6vxiwWKLKdSFklatn_7E-VvqIszXdbrwCIDhmwaAp8R3IsJPsVKwoafEP40x2IuAagk-vysavNQ=s0-d-e1-ft#https://github.com/notifications/beacon/ASkHhFFswsvqcGruje2ivD0jC6XfTkjsks5rmEBSgaJpZM4MX194.gif>

@sashahilton00
Copy link
Member Author

Comment by joerg-krause
Wednesday Mar 15, 2017 at 20:34 GMT


Yes, 256 is the resolution if the range is from 0 to 255. The resolution is used to get the factor wrt the spotify resolution, which is 65536 / 256 = 256 in this case. If the max spotify volume of 65535 is set this results in 65535 / 256 = 255.99..., which is truncated to 255 because of the Integer. But I can see now what you mean. I need to add 1 to the spotify volume and substract it after the division: ((65535 + 1) / 256) - 1 = 255.

I will update the commit tomorrow.

@sashahilton00
Copy link
Member Author

Comment by joerg-krause
Thursday Mar 16, 2017 at 08:31 GMT


@jsopenrb I've updated the volume calculation...

@sashahilton00
Copy link
Member Author

Comment by jsopenrb
Thursday Mar 16, 2017 at 08:56 GMT


Better, but it will still fail for certain volume ranges like 190. I think the proper solution it to switch to float calculations. Not a big deal at the moment.

@sashahilton00
Copy link
Member Author

Comment by plietar
Thursday Mar 16, 2017 at 13:33 GMT


Unfortunately I don't have much time at the moment to test this, it'll have to wait another week or two.

FWIW, I've previously used the following code to set the volume, which seemed to produced good results on my Pi's builtin audio output

    let (min, max) = elem.get_playback_db_range();
    let db_volume = if volume == 0 {
        min
    } else {
        let volume = volume as f64 / 65535.;
        let volume = volume.log10() * 6000.;
        MilliBel(volume as i64) + max
    };

    self.elem.set_playback_db_all(db_volume, alsa::Round::Ceil).unwrap();

@sashahilton00
Copy link
Member Author

Comment by joerg-krause
Thursday Mar 16, 2017 at 14:09 GMT


No, problem! Take your time. I'll check your volume setting...

@sashahilton00
Copy link
Member Author

Comment by jsopenrb
Friday Mar 17, 2017 at 19:42 GMT


That volume setting assumes that minimal dB value is mute which is not true for all cards.
get_normalized_volume/set_normalized_volume from alsa-utils have full implementation and handle both cases of minimum dB values:
http://git.alsa-project.org/?p=alsa-utils.git;a=blob;f=alsamixer/volume_mapping.c;h=1c0d7c45e6686239464e1b0bbc8983ea57f3914f;hb=HEAD
Shouldn't be too hard to rewrite those :)

@sashahilton00
Copy link
Member Author

Comment by joerg-krause
Thursday Mar 23, 2017 at 08:12 GMT


snd_mixer_selem_get_playback_dB_range() only worka for hardware mixers, but not for the ALSA softvol plugin where snd_ctl_get_dB_range() has to be used to get the db range of the control element.

This is the relevant code, how the handling of hardware and software mixer is done in shairtport-sync: https://github.com/mikebrady/shairport-sync/blob/master/audio_alsa.c#L358-L396. The ALSA softvol plugin is handled as a special case of a hardware mixer. The software mixer is used if no hardware mixer and no ALSA softvol plugin is used.

Note, shairport-sync uses an own attenuation curve, which is mapped onto the mixer. That's make the volume handling more complex than it is necessary for librespot.

For hardware mixer, we need a logarithmic curve, but not for the ALSA softvol plugin, as it already maps the linear volume value to a logarithmic curve.

So, maybe we need to split the mixer into two mixers: alsa and alsasoftvol?

@ytzelf
Copy link

ytzelf commented Jul 5, 2018

Hi everyone,

Has anything been done on the topic? I see mixer still has only softmixer.rs (and mod.rs - what's that?). I'm having mpd and librespot on the same machine and the fact that librespot volume is not linked to alsa mixer is a bit annoying. Not much of a coder myself but maybe there's anything I can do to help?

Thanks a lot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants