Make alsamixer less verbose

This commit is contained in:
ashthespy 2020-03-04 15:46:32 +01:00 committed by Sasha Hilton
parent 527a4ccbe2
commit 46328810cb

View file

@ -5,6 +5,8 @@ use std::error::Error;
use alsa; use alsa;
const SND_CTL_TLV_DB_GAIN_MUTE: i64 = -9999999;
#[derive(Clone)] #[derive(Clone)]
struct AlsaMixerVolumeParams { struct AlsaMixerVolumeParams {
min: i64, min: i64,
@ -29,11 +31,17 @@ impl AlsaMixer {
f64::from(vol - min) / f64::from(max - min) f64::from(vol - min) / f64::from(max - min)
} }
fn init_mixer(mut config: MixerConfig) -> Result<AlsaMixer, Box<Error>> { fn init_mixer(mut config: MixerConfig) -> Result<AlsaMixer, Box<dyn Error>> {
let mixer = alsa::mixer::Mixer::new(&config.card, false)?; let mixer = alsa::mixer::Mixer::new(&config.card, false)?;
let sid = alsa::mixer::SelemId::new(&config.mixer, config.index); let sid = alsa::mixer::SelemId::new(&config.mixer, config.index);
let selem = mixer.find_selem(&sid).expect("Couldn't find SelemId"); let selem = mixer.find_selem(&sid).expect(
format!(
"Couldn't find simple mixer control for {},{}",
&config.mixer, &config.index,
)
.as_str(),
);
let (min, max) = selem.get_playback_volume_range(); let (min, max) = selem.get_playback_volume_range();
let (min_db, max_db) = selem.get_playback_db_range(); let (min_db, max_db) = selem.get_playback_db_range();
let hw_mix = selem let hw_mix = selem
@ -41,7 +49,7 @@ impl AlsaMixer {
.is_ok(); .is_ok();
info!( info!(
"Alsa min: {} ({:?}[dB]) -- max: {} ({:?}[dB]) HW: {:?}", "Alsa Mixer info min: {} ({:?}[dB]) -- max: {} ({:?}[dB]) HW: {:?}",
min, min_db, max, max_db, hw_mix min, min_db, max, max_db, hw_mix
); );
@ -55,6 +63,10 @@ impl AlsaMixer {
info!("Using Alsa linear volume"); info!("Using Alsa linear volume");
} }
if min_db != alsa::mixer::MilliBel(SND_CTL_TLV_DB_GAIN_MUTE) {
debug!("Alsa min-db is not SND_CTL_TLV_DB_GAIN_MUTE!!");
}
Ok(AlsaMixer { Ok(AlsaMixer {
config: config, config: config,
params: AlsaMixerVolumeParams { params: AlsaMixerVolumeParams {
@ -67,75 +79,85 @@ impl AlsaMixer {
}) })
} }
fn map_volume(&self, set_volume: Option<u16>) -> Result<(u16), Box<Error>> { fn map_volume(&self, set_volume: Option<u16>) -> Result<u16, Box<dyn Error>> {
let mixer = alsa::mixer::Mixer::new(&self.config.card, false)?; let mixer = alsa::mixer::Mixer::new(&self.config.card, false)?;
let sid = alsa::mixer::SelemId::new(&*self.config.mixer, self.config.index); let sid = alsa::mixer::SelemId::new(&*self.config.mixer, self.config.index);
let selem = mixer.find_selem(&sid).expect("Couldn't find SelemId"); let selem = mixer.find_selem(&sid).unwrap();
let cur_vol = selem let cur_vol = selem
.get_playback_volume(alsa::mixer::SelemChannelId::mono()) .get_playback_volume(alsa::mixer::SelemChannelId::mono())
.expect("Couldn't get current volume"); .expect("Couldn't get current volume");
let cur_vol_db = selem let cur_vol_db = selem
.get_playback_vol_db(alsa::mixer::SelemChannelId::mono()) .get_playback_vol_db(alsa::mixer::SelemChannelId::mono())
.unwrap_or(alsa::mixer::MilliBel(9999)); .unwrap_or(alsa::mixer::MilliBel(-SND_CTL_TLV_DB_GAIN_MUTE));
let new_vol: u16; let mut new_vol: u16 = 0;
info!("Current alsa volume: {}[i64] {:?}", cur_vol, cur_vol_db); trace!("Current alsa volume: {}{:?}", cur_vol, cur_vol_db);
if let Some(vol) = set_volume { match set_volume {
if self.config.mapped_volume { Some(vol) => {
info!("Using mapped_volume"); if self.config.mapped_volume {
//TODO Check if min is not mute! // Cubic mapping ala alsamixer
let vol_db = ((self.pvol(vol, 0x0000, 0xFFFF)).log10() * 6000.0).floor() as i64 // https://linux.die.net/man/1/alsamixer
+ self.params.max; // In alsamixer, the volume is mapped to a value that is more natural for a
selem // human ear. The mapping is designed so that the position in the interval is
.set_playback_volume_all(vol_db) // proportional to the volume as a human ear would perceive it, i.e. the
.expect("Couldn't set alsa dB volume"); // position is the cubic root of the linear sample multiplication factor. For
info!( // controls with a small range (24 dB or less), the mapping is linear in the dB
"Mapping volume [{:.3}%] {:?} [u16] ->> Alsa [{:.3}%] {:?} [dB]", // values so that each step has the same size visually. TODO
self.pvol(vol, 0x0000, 0xFFFF) * 100.0, // TODO: Check if min is not mute!
vol, let vol_db = (self.pvol(vol, 0x0000, 0xFFFF).log10() * 6000.0).floor() as i64
+ self.params.max_db.0;
selem
.set_playback_db_all(alsa::mixer::MilliBel(vol_db), alsa::Round::Floor)
.expect("Couldn't set alsa dB volume");
debug!(
"Mapping volume [{:.3}%] {:?} [u16] ->> Alsa [{:.3}%] {:?} [dB] - {} [i64]",
self.pvol(vol, 0x0000, 0xFFFF) * 100.0,
vol,
self.pvol(
vol_db as f64,
self.params.min as f64,
self.params.max as f64
) * 100.0,
vol_db as f64 / 100.0,
vol_db
);
} else {
// Linear mapping
let alsa_volume =
((vol as f64 / 0xFFFF as f64) * self.params.range) as i64 + self.params.min;
selem
.set_playback_volume_all(alsa_volume)
.expect("Couldn't set alsa raw volume");
debug!(
"Mapping volume [{:.3}%] {:?} [u16] ->> Alsa [{:.3}%] {:?} [i64]",
self.pvol(vol, 0x0000, 0xFFFF) * 100.0,
vol,
self.pvol(
alsa_volume as f64,
self.params.min as f64,
self.params.max as f64
) * 100.0,
alsa_volume
);
};
}
None => {
new_vol = (((cur_vol - self.params.min) as f64 / self.params.range) * 0xFFFF as f64)
as u16;
debug!(
"Mapping volume [{:.3}%] {:?} [u16] <<- Alsa [{:.3}%] {:?} [i64]",
self.pvol(new_vol, 0x0000, 0xFFFF),
new_vol,
self.pvol( self.pvol(
vol_db as f64, cur_vol as f64,
self.params.min_db.to_db() as f64,
self.params.max_db.to_db() as f64
) * 100.0,
vol_db as f64 / 100.0,
);
} else {
info!("Using linear vol");
let alsa_volume =
((vol as f64 / 0xFFFF as f64) * self.params.range) as i64 + self.params.min;
selem
.set_playback_volume_all(alsa_volume)
.expect("Couldn't set alsa raw volume");
info!(
"Mapping volume [{:.3}%] {:?} [u16] ->> Alsa [{:.3}%] {:?} [i64]",
self.pvol(vol, 0x0000, 0xFFFF) * 100.0,
vol,
self.pvol(
alsa_volume as f64,
self.params.min as f64, self.params.min as f64,
self.params.max as f64 self.params.max as f64
) * 100.0, ),
alsa_volume cur_vol
); );
}; }
new_vol = vol; // Meh
} else {
new_vol =
(((cur_vol - self.params.min) as f64 / self.params.range) * 0xFFFF as f64) as u16;
info!(
"Mapping volume [{:.3}%] {:?} [u16] <<- Alsa [{:.3}%] {:?} [i64]",
self.pvol(new_vol, 0x0000, 0xFFFF),
new_vol,
self.pvol(
cur_vol as f64,
self.params.min as f64,
self.params.max as f64
),
cur_vol
);
} }
Ok(new_vol) Ok(new_vol)