feat(volume): Added volume mapping
This commit is contained in:
parent
b470337e0a
commit
dce81d4266
@ -3,6 +3,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
|
|
||||||
@ -10,6 +11,8 @@
|
|||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
#include "utils/threading.hpp"
|
#include "utils/threading.hpp"
|
||||||
|
|
||||||
|
#define MAX_LINEAR_DB_SCALE 24
|
||||||
|
|
||||||
LEMONBUDDY_NS
|
LEMONBUDDY_NS
|
||||||
|
|
||||||
DEFINE_ERROR(alsa_exception);
|
DEFINE_ERROR(alsa_exception);
|
||||||
@ -64,7 +67,9 @@ class alsa_mixer {
|
|||||||
int process_events();
|
int process_events();
|
||||||
|
|
||||||
int get_volume();
|
int get_volume();
|
||||||
|
int get_normalized_volume();
|
||||||
void set_volume(float percentage);
|
void set_volume(float percentage);
|
||||||
|
void set_normalized_volume(float percentage);
|
||||||
void set_mute(bool mode);
|
void set_mute(bool mode);
|
||||||
void toggle_mute();
|
void toggle_mute();
|
||||||
bool is_muted();
|
bool is_muted();
|
||||||
|
@ -57,6 +57,8 @@ namespace modules {
|
|||||||
|
|
||||||
int m_headphoneid = 0;
|
int m_headphoneid = 0;
|
||||||
|
|
||||||
|
bool m_mapped;
|
||||||
|
|
||||||
stateflag m_muted{false};
|
stateflag m_muted{false};
|
||||||
stateflag m_headphones{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;
|
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) {
|
void alsa_mixer::set_volume(float percentage) {
|
||||||
if (is_muted())
|
if (is_muted())
|
||||||
return;
|
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);
|
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) {
|
void alsa_mixer::set_mute(bool mode) {
|
||||||
std::lock_guard<threading_util::spin_lock> guard(m_lock);
|
std::lock_guard<threading_util::spin_lock> guard(m_lock);
|
||||||
snd_mixer_selem_set_playback_switch_all(m_mixerelement, mode);
|
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(), master_mixer_name, "master-mixer");
|
||||||
GET_CONFIG_VALUE(name(), speaker_mixer_name, "speaker-mixer");
|
GET_CONFIG_VALUE(name(), speaker_mixer_name, "speaker-mixer");
|
||||||
GET_CONFIG_VALUE(name(), headphone_mixer_name, "headphone-mixer");
|
GET_CONFIG_VALUE(name(), headphone_mixer_name, "headphone-mixer");
|
||||||
|
m_mapped = m_conf.get<bool>(name(), "mapped", false);
|
||||||
|
|
||||||
if (!headphone_mixer_name.empty())
|
if (!headphone_mixer_name.empty())
|
||||||
REQ_CONFIG_VALUE(name(), m_headphoneid, "headphone-id");
|
REQ_CONFIG_VALUE(name(), m_headphoneid, "headphone-id");
|
||||||
@ -110,16 +111,19 @@ namespace modules {
|
|||||||
m_headphones = false;
|
m_headphones = false;
|
||||||
|
|
||||||
if (m_mixers[mixer::MASTER]) {
|
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();
|
m_muted = m_muted || m_mixers[mixer::MASTER]->is_muted();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_controls[control::HEADPHONE] && m_controls[control::HEADPHONE]->test_device_plugged()) {
|
if (m_controls[control::HEADPHONE] && m_controls[control::HEADPHONE]->test_device_plugged()) {
|
||||||
m_headphones = true;
|
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();
|
m_muted = m_muted || m_mixers[mixer::HEADPHONE]->is_muted();
|
||||||
} else if (m_mixers[mixer::SPEAKER]) {
|
} 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();
|
m_muted = m_muted || m_mixers[mixer::SPEAKER]->is_muted();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,11 +200,15 @@ namespace modules {
|
|||||||
}
|
}
|
||||||
} else if (cmd.compare(0, strlen(EVENT_VOLUME_UP), EVENT_VOLUME_UP) == 0) {
|
} else if (cmd.compare(0, strlen(EVENT_VOLUME_UP), EVENT_VOLUME_UP) == 0) {
|
||||||
for (auto&& mixer : mixers) {
|
for (auto&& mixer : mixers) {
|
||||||
mixer->set_volume(math_util::cap<float>(mixer->get_volume() + 5, 0, 100));
|
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) {
|
} else if (cmd.compare(0, strlen(EVENT_VOLUME_DOWN), EVENT_VOLUME_DOWN) == 0) {
|
||||||
for (auto&& mixer : mixers) {
|
for (auto&& mixer : mixers) {
|
||||||
mixer->set_volume(math_util::cap<float>(mixer->get_volume() - 5, 0, 100));
|
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 {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user