From 78e2d9642f8c30fe63c1d8045721e345aad95ebc Mon Sep 17 00:00:00 2001 From: "Geoffrey D. Bennett" Date: Thu, 20 Feb 2025 23:41:16 +1030 Subject: [PATCH] Update alsa interface and gain widget to support linear volume # Conflicts: # src/alsa.c --- src/alsa-sim.c | 4 ++-- src/alsa.c | 16 +++++++------ src/alsa.h | 7 +++--- src/widget-gain.c | 58 +++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/src/alsa-sim.c b/src/alsa-sim.c index 0c2a55a..2d5fa3b 100644 --- a/src/alsa-sim.c +++ b/src/alsa-sim.c @@ -231,7 +231,7 @@ static void alsa_parse_comment_node( err = snd_config_get_integer(node, &dbmin); if (err < 0) fatal_alsa_error("snd_config_get_integer error", err); - elem->min_dB = dbmin / 100; + elem->min_cdB = dbmin; } else if (strcmp(key, "dbmax") == 0) { if (type != SND_CONFIG_TYPE_INTEGER) { printf("dbmax type not integer\n"); @@ -241,7 +241,7 @@ static void alsa_parse_comment_node( err = snd_config_get_integer(node, &dbmax); if (err < 0) fatal_alsa_error("snd_config_get_integer error", err); - elem->max_dB = dbmax / 100; + elem->max_cdB = dbmax; } } } diff --git a/src/alsa.c b/src/alsa.c index fd4fa7c..9e6fe3e 100644 --- a/src/alsa.c +++ b/src/alsa.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include +#include #include "alsa.h" #include "scarlett2-firmware.h" @@ -361,7 +362,7 @@ static void alsa_get_elem_tlv(struct alsa_elem *elem) { unsigned int tlv[MAX_TLV_RANGE_SIZE]; unsigned int *dbrec; int ret; - long min_dB, max_dB; + long min_cdB, max_cdB; snd_ctl_elem_id_alloca(&elem_id); snd_ctl_elem_id_set_numid(elem_id, elem->numid); @@ -370,29 +371,30 @@ static void alsa_get_elem_tlv(struct alsa_elem *elem) { elem->card->handle, elem_id, tlv, sizeof(tlv) ); if (ret < 0) { - fprintf(stderr, "TLV read error %d\n", ret); + fprintf(stderr, "TLV read error: %s\n", snd_strerror(ret)); return; } ret = snd_tlv_parse_dB_info(tlv, sizeof(tlv), &dbrec); if (ret <= 0) { - fprintf(stderr, "TLV parse error %d\n", ret); + fprintf(stderr, "TLV parse error: %s\n", snd_strerror(ret)); return; } 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); + ret = snd_tlv_get_dB_range(dbrec, min_val, max_val, &min_cdB, &max_cdB); if (ret != 0) { - fprintf(stderr, "TLV range error %d\n", ret); + fprintf(stderr, "TLV range error: %s\n", snd_strerror(ret)); return; } elem->min_val = min_val; elem->max_val = max_val; - elem->min_dB = min_dB / 100; - elem->max_dB = max_dB / 100; + elem->dB_type = dbrec[SNDRV_CTL_TLVO_TYPE]; + elem->min_cdB = min_cdB; + elem->max_cdB = max_cdB; } static void alsa_get_elem(struct alsa_card *card, int numid) { diff --git a/src/alsa.h b/src/alsa.h index 2d3eb02..a350965 100644 --- a/src/alsa.h +++ b/src/alsa.h @@ -126,11 +126,12 @@ struct alsa_elem { int count; int index; - // for gain/volume elements, the dB range and step + // for gain/volume elements, the value range, dB type, and dB range int min_val; int max_val; - int min_dB; - int max_dB; + int dB_type; + int min_cdB; + int max_cdB; // for routing sinks int is_routing_snk; diff --git a/src/widget-gain.c b/src/widget-gain.c index d72d570..71b92ac 100644 --- a/src/widget-gain.c +++ b/src/widget-gain.c @@ -4,6 +4,7 @@ #include "gtkdial.h" #include "stringhelper.h" #include "widget-gain.h" +#include "db.h" struct gain { struct alsa_elem *elem; @@ -56,16 +57,31 @@ static void gain_updated( char s[20]; char *p = s; - float value = (float)alsa_value * data->scale + elem->min_dB; + float value; + int min_db = round(elem->min_cdB / 100.0); + int max_db = round(elem->max_cdB / 100.0); - if (value > elem->max_dB) - value = elem->max_dB; - else if (value < elem->min_dB) - value = elem->min_dB; + if (elem->dB_type == SND_CTL_TLVT_DB_LINEAR) { + value = linear_value_to_db( + alsa_value, + elem->min_val, + elem->max_val, + min_db, + max_db + ); + } else { + value = ((float)(alsa_value - elem->min_val)) * data->scale + (elem->min_cdB / 100.0); + if (value > max_db) + value = max_db; + else if (value < min_db) + value = min_db; + } - if (data->zero_is_off && alsa_value == 0) { + if (data->zero_is_off && value == min_db) { p += sprintf(p, "−∞"); } else { + if (data->scale <= 0.5) + value = round(value * 10) / 10; if (value < 0) p += sprintf(p, "−"); else if (value > 0) @@ -159,20 +175,42 @@ GtkWidget *make_gain_alsa_elem( gtk_widget_set_valign(data->vbox, GTK_ALIGN_START); gtk_widget_set_vexpand(data->vbox, TRUE); - data->scale = (float)(elem->max_dB - elem->min_dB) / - (elem->max_val - elem->min_val); + gboolean is_linear = elem->dB_type == SND_CTL_TLVT_DB_LINEAR; + double step; + if (is_linear) { + data->scale = 0.5; + step = 0.5; + } else { + data->scale = (float)(elem->max_cdB - elem->min_cdB) / 100.0 / + (elem->max_val - elem->min_val); + step = 1; + } data->dial = gtk_dial_new_with_range( elem->min_val, elem->max_val, - 1, + step, 3 / data->scale ); // calculate 0dB value - int zero_db_value = (int)((0 - elem->min_dB) / data->scale + elem->min_val); + int zero_db_value; + + if (is_linear) { + zero_db_value = cdb_to_linear_value( + 0, + elem->min_val, + elem->max_val, + elem->min_cdB, + elem->max_cdB + ); + } else { + zero_db_value = + (int)((0 - elem->min_cdB) / 100.0 / data->scale + elem->min_val); + } gtk_dial_set_zero_db(GTK_DIAL(data->dial), zero_db_value); + gtk_dial_set_is_linear(GTK_DIAL(data->dial), is_linear); // convert from widget_taper to gtk_dial_taper int gtk_dial_taper;