Remove hard-coded values from widget-gain.c and widget-volume.c

Update alsa-sim.c and alsa.c to read the TLV info, and update the gain
and volume widgets to use that info rather than hard-coding the
min/max values.
This commit is contained in:
Geoffrey D. Bennett
2023-11-30 23:57:47 +10:30
parent 197f469bd8
commit be458afcc4
5 changed files with 116 additions and 16 deletions

View File

@@ -151,6 +151,42 @@ static void alsa_parse_comment_node(
elem->type = SND_CTL_ELEM_TYPE_INTEGER;
} else if (strcmp(key, "item") == 0) {
alsa_parse_enum_items(node, elem);
} else if (strcmp(key, "range") == 0) {
if (type != SND_CONFIG_TYPE_STRING) {
printf("range type not string\n");
return;
}
const char *range;
err = snd_config_get_string(node, &range);
if (err < 0)
fatal_alsa_error("snd_config_get_string error", err);
// Parse the range string and update elem->min_val and elem->max_val
int min_val, max_val;
if (sscanf(range, "%d - %d", &min_val, &max_val) == 2) {
elem->min_val = min_val;
elem->max_val = max_val;
}
} else if (strcmp(key, "dbmin") == 0) {
if (type != SND_CONFIG_TYPE_INTEGER) {
printf("dbmin type not integer\n");
return;
}
long dbmin;
err = snd_config_get_integer(node, &dbmin);
if (err < 0)
fatal_alsa_error("snd_config_get_integer error", err);
elem->min_dB = dbmin / 100;
} else if (strcmp(key, "dbmax") == 0) {
if (type != SND_CONFIG_TYPE_INTEGER) {
printf("dbmax type not integer\n");
return;
}
long dbmax;
err = snd_config_get_integer(node, &dbmax);
if (err < 0)
fatal_alsa_error("snd_config_get_integer error", err);
elem->max_dB = dbmax / 100;
}
}
}

View File

@@ -7,6 +7,8 @@
#include "stringhelper.h"
#include "window-iface.h"
#define MAX_TLV_RANGE_SIZE 256
// names for the port categories
const char *port_category_names[PC_COUNT] = {
"Hardware Outputs",
@@ -340,6 +342,54 @@ static void alsa_get_elem_list(struct alsa_card *card) {
if (strstr(alsa_elem.name, "Channel Map"))
continue;
// get TLV info if it's a volume control
if (alsa_elem.type == SND_CTL_ELEM_TYPE_INTEGER) {
snd_ctl_elem_info_t *elem_info;
snd_ctl_elem_info_alloca(&elem_info);
snd_ctl_elem_info_set_numid(elem_info, alsa_elem.numid);
snd_ctl_elem_info(card->handle, elem_info);
if (snd_ctl_elem_info_is_tlv_readable(elem_info)) {
snd_ctl_elem_id_t *elem_id;
unsigned int tlv[MAX_TLV_RANGE_SIZE];
unsigned int *dbrec;
int ret;
long min_dB, max_dB;
snd_ctl_elem_id_alloca(&elem_id);
snd_ctl_elem_id_set_numid(elem_id, alsa_elem.numid);
ret = snd_ctl_elem_tlv_read(
card->handle, elem_id, tlv, sizeof(tlv)
);
if (ret < 0) {
fprintf(stderr, "TLV read error %d\n", ret);
continue;
}
ret = snd_tlv_parse_dB_info(tlv, sizeof(tlv), &dbrec);
if (ret <= 0) {
fprintf(stderr, "TLV parse error %d\n", ret);
continue;
}
int min_val = snd_ctl_elem_info_get_min(elem_info);
int max_val = snd_ctl_elem_info_get_max(elem_info);
ret = snd_tlv_get_dB_range(tlv, min_val, max_val, &min_dB, &max_dB);
if (ret != 0) {
fprintf(stderr, "TLV range error %d\n", ret);
continue;
}
alsa_elem.min_val = min_val;
alsa_elem.max_val = max_val;
alsa_elem.min_dB = min_dB / 100;
alsa_elem.max_dB = max_dB / 100;
}
}
if (card->elems->len <= alsa_elem.numid)
g_array_set_size(card->elems, alsa_elem.numid + 1);
g_array_index(card->elems, struct alsa_elem, alsa_elem.numid) = alsa_elem;

View File

@@ -115,6 +115,12 @@ struct alsa_elem {
int type;
int count;
// for gain/volume elements, the dB range and step
int min_val;
int max_val;
int min_dB;
int max_dB;
// for the number (or translated letter; A = 1) in the item name
// TODO: move this to struct routing_snk?
int lr_num;

View File

@@ -4,11 +4,6 @@
#include "gtkdial.h"
#include "widget-gain.h"
// gain controls -80dB - +6dB, 0.5dB steps
#define DIAL_MIN_VALUE 0
#define DIAL_MAX_VALUE 172
#define DIAL_ZERO_DB_VALUE 160
static void gain_changed(GtkWidget *widget, struct alsa_elem *elem) {
int value = gtk_dial_get_value(GTK_DIAL(widget));
@@ -23,7 +18,10 @@ static void gain_updated(struct alsa_elem *elem) {
gtk_dial_set_value(GTK_DIAL(elem->widget), value);
char s[20];
snprintf(s, 20, "%.1f", (value / 2.0) - 80);
float scale = (float)(elem->max_dB - elem->min_dB) /
(elem->max_val - elem->min_val);
snprintf(s, 20, "%.1f", value * scale + elem->min_dB);
gtk_label_set_text(GTK_LABEL(elem->widget2), s);
}
@@ -32,9 +30,15 @@ GtkWidget *make_gain_alsa_elem(struct alsa_elem *elem) {
gtk_widget_set_hexpand(vbox, TRUE);
GtkWidget *dial = gtk_dial_new_with_range(
DIAL_MIN_VALUE, DIAL_MAX_VALUE, 1
elem->min_val, elem->max_val, 1
);
gtk_dial_set_zero_db(GTK_DIAL(dial), DIAL_ZERO_DB_VALUE);
// calculate 0dB value from min/max dB and min/max value
float scale = (float)(elem->max_dB - elem->min_dB) /
(elem->max_val - elem->min_val);
int zero_db_value = (int)((0 - elem->min_dB) / scale + elem->min_val);
gtk_dial_set_zero_db(GTK_DIAL(dial), zero_db_value);
gtk_widget_set_vexpand(dial, TRUE);

View File

@@ -4,11 +4,6 @@
#include "gtkdial.h"
#include "widget-volume.h"
// volume controls -127dB - 0dB
#define DIAL_MIN_VALUE 0
#define DIAL_MAX_VALUE 127
#define DIAL_ZERO_DB_VALUE 127
static void volume_changed(GtkWidget *widget, struct alsa_elem *elem) {
int value = gtk_dial_get_value(GTK_DIAL(widget));
@@ -23,7 +18,10 @@ static void volume_updated(struct alsa_elem *elem) {
gtk_dial_set_value(GTK_DIAL(elem->widget), value);
char s[20];
snprintf(s, 20, "%ddB", value - 127);
float scale = (float)(elem->max_dB - elem->min_dB) /
(elem->max_val - elem->min_val);
snprintf(s, 20, "%ddB", (int)(value * scale + elem->min_dB));
gtk_label_set_text(GTK_LABEL(elem->widget2), s);
}
@@ -32,9 +30,15 @@ GtkWidget *make_volume_alsa_elem(struct alsa_elem *elem) {
gtk_widget_set_hexpand(vbox, TRUE);
GtkWidget *dial = gtk_dial_new_with_range(
DIAL_MIN_VALUE, DIAL_MAX_VALUE, 1
elem->min_val, elem->max_val, 1
);
gtk_dial_set_zero_db(GTK_DIAL(dial), DIAL_ZERO_DB_VALUE);
// calculate 0dB value from min/max dB and min/max value
float scale = (float)(elem->max_dB - elem->min_dB) /
(elem->max_val - elem->min_val);
int zero_db_value = (int)((0 - elem->min_dB) / scale + elem->min_val);
gtk_dial_set_zero_db(GTK_DIAL(dial), zero_db_value);
gtk_widget_set_vexpand(dial, TRUE);