feat(volume): Added volume mapping
This commit is contained in:
parent
b470337e0a
commit
dce81d4266
@ -3,6 +3,7 @@
|
||||
#include <stdio.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
@ -10,6 +11,8 @@
|
||||
#include "config.hpp"
|
||||
#include "utils/threading.hpp"
|
||||
|
||||
#define MAX_LINEAR_DB_SCALE 24
|
||||
|
||||
LEMONBUDDY_NS
|
||||
|
||||
DEFINE_ERROR(alsa_exception);
|
||||
@ -64,7 +67,9 @@ class alsa_mixer {
|
||||
int process_events();
|
||||
|
||||
int get_volume();
|
||||
int get_normalized_volume();
|
||||
void set_volume(float percentage);
|
||||
void set_normalized_volume(float percentage);
|
||||
void set_mute(bool mode);
|
||||
void toggle_mute();
|
||||
bool is_muted();
|
||||
|
@ -57,6 +57,8 @@ namespace modules {
|
||||
|
||||
int m_headphoneid = 0;
|
||||
|
||||
bool m_mapped;
|
||||
|
||||
stateflag m_muted{false};
|
||||
stateflag m_headphones{false};
|
||||
|
||||
|
@ -169,6 +169,35 @@ int alsa_mixer::get_volume() {
|
||||
return 100.0f * (vol_total / chan_n) / vol_max + 0.5f;
|
||||
}
|
||||
|
||||
int alsa_mixer::get_normalized_volume() {
|
||||
std::lock_guard<threading_util::spin_lock> guard(m_lock);
|
||||
long chan_n = 0, vol_total = 0, vol, vol_min, vol_max;
|
||||
double normalized, min_norm;
|
||||
|
||||
snd_mixer_selem_get_playback_dB_range(m_mixerelement, &vol_min, &vol_max);
|
||||
|
||||
for (int i = 0; i <= SND_MIXER_SCHN_LAST; i++) {
|
||||
if (snd_mixer_selem_has_playback_channel(
|
||||
m_mixerelement, static_cast<snd_mixer_selem_channel_id_t>(i))) {
|
||||
snd_mixer_selem_get_playback_dB(
|
||||
m_mixerelement, static_cast<snd_mixer_selem_channel_id_t>(i), &vol);
|
||||
vol_total += vol;
|
||||
chan_n++;
|
||||
}
|
||||
}
|
||||
|
||||
if (vol_max - vol_min <= MAX_LINEAR_DB_SCALE * 100)
|
||||
return 100.0f * (vol_total / chan_n - vol_min) / (vol_max - vol_min) + 0.5f;
|
||||
|
||||
normalized = pow10((vol_total / chan_n - vol_max) / 6000.0);
|
||||
if (vol_min != SND_CTL_TLV_DB_GAIN_MUTE) {
|
||||
min_norm = pow10((vol_min - vol_max) / 6000.0);
|
||||
normalized = (normalized - min_norm) / (1 - min_norm);
|
||||
}
|
||||
|
||||
return 100.0f * normalized + 0.5f;
|
||||
}
|
||||
|
||||
void alsa_mixer::set_volume(float percentage) {
|
||||
if (is_muted())
|
||||
return;
|
||||
@ -181,6 +210,31 @@ void alsa_mixer::set_volume(float percentage) {
|
||||
snd_mixer_selem_set_playback_volume_all(m_mixerelement, vol_max * percentage / 100);
|
||||
}
|
||||
|
||||
void alsa_mixer::set_normalized_volume(float percentage) {
|
||||
if (is_muted())
|
||||
return;
|
||||
|
||||
std::lock_guard<threading_util::spin_lock> guard(m_lock);
|
||||
|
||||
long vol_min, vol_max;
|
||||
double min_norm;
|
||||
percentage = percentage / 100.0f;
|
||||
|
||||
snd_mixer_selem_get_playback_dB_range(m_mixerelement, &vol_min, &vol_max);
|
||||
|
||||
if (vol_max - vol_min <= MAX_LINEAR_DB_SCALE * 100) {
|
||||
snd_mixer_selem_set_playback_dB_all(m_mixerelement, lrint(percentage * (vol_max - vol_min)) + vol_min, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vol_min != SND_CTL_TLV_DB_GAIN_MUTE) {
|
||||
min_norm = pow10((vol_min - vol_max) / 6000.0);
|
||||
percentage = percentage * (1 - min_norm) + min_norm;
|
||||
}
|
||||
|
||||
snd_mixer_selem_set_playback_dB_all(m_mixerelement, lrint(6000.0 * log10(percentage)) + vol_max, 0);
|
||||
}
|
||||
|
||||
void alsa_mixer::set_mute(bool mode) {
|
||||
std::lock_guard<threading_util::spin_lock> guard(m_lock);
|
||||
snd_mixer_selem_set_playback_switch_all(m_mixerelement, mode);
|
||||
|
@ -14,6 +14,7 @@ namespace modules {
|
||||
GET_CONFIG_VALUE(name(), master_mixer_name, "master-mixer");
|
||||
GET_CONFIG_VALUE(name(), speaker_mixer_name, "speaker-mixer");
|
||||
GET_CONFIG_VALUE(name(), headphone_mixer_name, "headphone-mixer");
|
||||
m_mapped = m_conf.get<bool>(name(), "mapped", false);
|
||||
|
||||
if (!headphone_mixer_name.empty())
|
||||
REQ_CONFIG_VALUE(name(), m_headphoneid, "headphone-id");
|
||||
@ -110,16 +111,19 @@ namespace modules {
|
||||
m_headphones = false;
|
||||
|
||||
if (m_mixers[mixer::MASTER]) {
|
||||
m_volume = m_volume * m_mixers[mixer::MASTER]->get_volume() / 100.0f;
|
||||
m_volume = m_volume * (m_mapped ? m_mixers[mixer::MASTER]->get_normalized_volume() / 100.0f :
|
||||
m_mixers[mixer::MASTER]->get_volume() / 100.0f);
|
||||
m_muted = m_muted || m_mixers[mixer::MASTER]->is_muted();
|
||||
}
|
||||
|
||||
if (m_controls[control::HEADPHONE] && m_controls[control::HEADPHONE]->test_device_plugged()) {
|
||||
m_headphones = true;
|
||||
m_volume = m_volume * m_mixers[mixer::HEADPHONE]->get_volume() / 100.0f;
|
||||
m_volume = m_volume * (m_mapped ? m_mixers[mixer::HEADPHONE]->get_normalized_volume() / 100.0f :
|
||||
m_mixers[mixer::HEADPHONE]->get_volume() / 100.0f);
|
||||
m_muted = m_muted || m_mixers[mixer::HEADPHONE]->is_muted();
|
||||
} else if (m_mixers[mixer::SPEAKER]) {
|
||||
m_volume = m_volume * m_mixers[mixer::SPEAKER]->get_volume() / 100.0f;
|
||||
m_volume = m_volume * (m_mapped ? m_mixers[mixer::SPEAKER]->get_normalized_volume() / 100.0f :
|
||||
m_mixers[mixer::SPEAKER]->get_volume() / 100.0f);
|
||||
m_muted = m_muted || m_mixers[mixer::SPEAKER]->is_muted();
|
||||
}
|
||||
|
||||
@ -196,10 +200,14 @@ namespace modules {
|
||||
}
|
||||
} else if (cmd.compare(0, strlen(EVENT_VOLUME_UP), EVENT_VOLUME_UP) == 0) {
|
||||
for (auto&& mixer : mixers) {
|
||||
m_mapped ?
|
||||
mixer->set_normalized_volume(math_util::cap<float>(mixer->get_normalized_volume() + 5, 0, 100)) :
|
||||
mixer->set_volume(math_util::cap<float>(mixer->get_volume() + 5, 0, 100));
|
||||
}
|
||||
} else if (cmd.compare(0, strlen(EVENT_VOLUME_DOWN), EVENT_VOLUME_DOWN) == 0) {
|
||||
for (auto&& mixer : mixers) {
|
||||
m_mapped ?
|
||||
mixer->set_normalized_volume(math_util::cap<float>(mixer->get_normalized_volume() - 5, 0, 100)) :
|
||||
mixer->set_volume(math_util::cap<float>(mixer->get_volume() - 5, 0, 100));
|
||||
}
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user